package com.hmdp.utils;

import cn.hutool.core.lang.UUID;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;

import java.util.Collections;
import java.util.concurrent.TimeUnit;

/**
 * 锁的实现类
 */
public class SimpleRedisLock implements ILock{

	private String name;

	private StringRedisTemplate stringRedisTemplate;

	//这两个参数由调用者传递过来，所以此处需要单独定义构造函数
	public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {
		this.name = name;
		this.stringRedisTemplate = stringRedisTemplate;
	}

	private static final String KEY_PREFIX = "lock:";
	private static final String ID_PREFIX = UUID.randomUUID().toString(true)+"-";
	private static final DefaultRedisScript< Long> unlockScript;//创建一个脚本
	//这里的静态代码库作用是项目一运行就加载这个lua脚本文件，提高性能
	static {
		unlockScript = new DefaultRedisScript<>();//创建一个脚本
		unlockScript.setLocation(new ClassPathResource("unlock.lua"));//设置脚本位置
		unlockScript.setResultType(Long.class);//设置返回类型
	}

	@Override
	public boolean tryLock(Long timeoutSec) {
		// 获取线程标示
		String threadId =ID_PREFIX + Thread.currentThread().getId();
		// 获取锁
		Boolean success = stringRedisTemplate.opsForValue()
				.setIfAbsent(KEY_PREFIX + name, threadId, timeoutSec, TimeUnit.SECONDS);
		return Boolean.TRUE.equals(success);
	}

	//利用lua脚本来解决极端情况下锁提前释放的问题，保证原子性
	@Override
	public void unLock() {
		//判断线程id和执行释放锁在脚本中执行，可以保证原子性
		// 调用lua脚本
		stringRedisTemplate.execute(
				unlockScript,//指定脚本
				Collections.singletonList(KEY_PREFIX + name),//指定key
				ID_PREFIX + Thread.currentThread().getId());//获取线程标识
	}

	/*@Override
	public void unLock() {
		//获取线程标识
		String threadId = ID_PREFIX + Thread.currentThread().getId();
		//获取锁中的标识
		String id = stringRedisTemplate.opsForValue().get(KEY_PREFIX + name);
		if (threadId.equals(id)) {
			//释放锁
			stringRedisTemplate.delete(KEY_PREFIX + name);
		}
	}*/
}
